//==============================================================================
// Routines to set up the separate thread for the TCP connection 
// and to set up the TCP client interface to TCPControl   
//==============================================================================
                        
#include "MP.h"

//==============================================================================
// Routine to convert an IP host to an IP address
//==============================================================================
void Ttcp_converthostname(char *mod, char *host)
{ int i,j;
  int iResult;
  char str[MAX_STRING];
  struct hostent *remoteHost;
  struct in_addr addr;

  //
  // Check if IP address is a .'d address or a name
  // if it's a name convert it to an IP address
  //
  j=0; for (i=0;i<strlen(host);i++) { if (host[i]=='.') j=1; }
    
  if (j==0) // not an ip address
    { remoteHost = gethostbyname(host);
      if (remoteHost == NULL) 
        { iResult=WSAGetLastError(); 
          sprintf(str,"gethostbyname Failed: %ld",iResult); 
          MP_errlog(mod,str);
        }
      else
        { if (remoteHost->h_addrtype!=AF_INET) MP_errlog(mod,"Hostname is not an INET host");
          else
            { i = 0;
              while (remoteHost->h_addr_list[i] != 0) 
                { addr.s_addr = *(u_long *) remoteHost->h_addr_list[i++];
                  strcpy(host,inet_ntoa(addr));
                  sprintf(str,"\tIP Address #%d: %s", i,host );
                  MP_log(mod,str);
                  break; // only use the first one
                }
            }
        }         
    }
}
  
  
//==============================================================================
// Routine to set up the TCP client interface to wifiRemote & MediaPortal
// This is called from 2 different threads so needs to be re-entrant   
//==============================================================================
extern DWORD __stdcall Ttcp_client(LPVOID lpdwThreadParam)
{
    // Declare and initialize variables.
    WSADATA wsaData;
    int iResult;
    struct sockaddr_in clientService; 
    char recvbuf[MAX_BUFLEN],str[MAX_STRING],mod[256];
    int i;
    int server;
    int firstcall=0;
    
    server=*((int *)lpdwThreadParam);
    if (server==WIFIREMOTE) strcpy(mod,"TCP[Wifi]:");
    else strcpy(mod,"TCP[MPEx]:");
    MP_logl(3,"Thread started:",mod);

    while (1)
      { 
        for (i=0; i<50; i++) { if (program_finished==1) return; else Sleep(100); } // Wait 5 secs and retry
        // Initialise
        ConnectSocket[server] = INVALID_SOCKET;
        MP_Global_connecting[server]=1;    
        MP_Global_connected[server]=0;
                
        // Initialize Winsock
        iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
        if (iResult != NO_ERROR) 
         { sprintf(str,"WSAStartup failed: %d", iResult); MP_errlog(mod,str); }
        else  
         { // Create a SOCKET for connecting to server
           ConnectSocket[server] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
           if (ConnectSocket[server] == INVALID_SOCKET) 
             { sprintf(str,"Error at socket(): %ld", WSAGetLastError() ); MP_errlog(mod,str); }
           else
             {
               // The sockaddr_in structure specifies the address family,
               // IP address, and port of the server to be connected to.
               clientService.sin_family = AF_INET;
               Ttcp_converthostname(mod,MP_Global_IPAddress[server].i); // make sure it's an IP address
             //    clientService.sin_addr.s_addr = inet_addr( TCPCONTROLLER_INET_ADDR );
               //    clientService.sin_port = htons( TCPCONTROLLER_PORT_NUMBER );
               clientService.sin_addr.s_addr = inet_addr( MP_Global_IPAddress[server].i );
               clientService.sin_port = htons( MP_Global_Port[server] );
               // Connect to server.
               MP_logl(2,mod,"Connecting......");
               iResult = connect( ConnectSocket[server], (SOCKADDR*) &clientService, sizeof(clientService) );
               if ( iResult == SOCKET_ERROR) 
                 { iResult=WSAGetLastError(); 
                   sprintf(str,"Connect Failed: Error at connect(): %ld",iResult); 
                   if ((iResult!=WSAETIMEDOUT) && (iResult!=WSAECONNREFUSED)) MP_errlog(mod,str);
                 }
               else 
                 {  MP_Global_connected[server]=1; MP_Global_connecting[server]=0;
                    MP_logl(3,mod,"Connection Established");
                    // Receive and handle until the peer closes the connection
                    if (server==MPEXTENDED) {  MP_Extended_request_recordings(server,mod); }
    
                    do { iResult = MP_recv(mod,server, recvbuf, MAX_BUFLEN);
                         if ( iResult > 0 ) 
                           { recvbuf[iResult]='\0';
                             if (iResult>(MAX_BUFLEN-2)) MP_errlog(mod,"Receive buffer overflow");
//                            sprintf(str,"%d bytes recvd",iResult); 
//                            MP_log("TCPIO:",str);
//                            MP_log("TCPIO:",recvbuf);
                             remove_utf8((unsigned char *)recvbuf); // remove any utf-8 characters
                             if (server==WIFIREMOTE) 
                               { MP_WifiRemote_Decode(mod,recvbuf);  // decode the message for display
                               }
                             else
                               { sprintf(str,"Got a message (%d bytes) from MPExtended",iResult); 
                                 MP_logl(3,mod,str);
                                 recvbuf[iResult]=0;
                                 MP_Extended_process_recordings(server,mod,recvbuf,iResult);
                                 Sleep(MP_Global_mWait*1000);
                                 MP_Extended_request_recordings(server,mod);
                               }
                           }
                         else if ( iResult == 0 ) { MP_Global_connected[server]=0; MP_log(mod,"Connection closed"); }
                         else 
                           { MP_Global_connected[server]=0; 
                             i=WSAGetLastError(); 
                             sprintf(str,"MP_recv Failed: Error at socket(): %ld",iResult);
                             MP_log(mod,str); 
                           }
                       } while( iResult > 0 );
                 }
               // cleanup
               MP_Global_connected[server]=0; MP_Global_connecting[server]=0;
               closesocket(ConnectSocket[server]);
             }
           MP_Global_connected[server]=0; MP_Global_connecting[server]=0; 
         }     
       MP_Global_connected[server]=0; MP_Global_connecting[server]=0;
       WSACleanup();
      }
}


//==============================================================================
// external routine to start the TCP handler threads
// This initiates separate thread to create the connection and handle the
//  messages from MediaPortal (WifiRemote) and MPExtended
//==============================================================================
extern int MP_Thread_Init() 
{
   DWORD dwThreadId[NUM_CONNECTIONS]; 
   static int i,server[NUM_CONNECTIONS];
   
   MP_logl(3,"MP_Thread_Init","Called");
   // Set flag to inicate we are connecting to avoid another call to Init
   for (i=0; i<NUM_CONNECTIONS; i++) { MP_Global_connecting[i]=1; server[i]=0; } 

   // Do the wifiRemote thread   
   server[WIFIREMOTE]=WIFIREMOTE;
   MP_logl(3,"Creating","WifiRemote Thread");
   if (CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&Ttcp_client,(LPVOID) &server[WIFIREMOTE],0,&dwThreadId[WIFIREMOTE]) == NULL)
        { MP_errlog("MP_Init","****Error Creating WifiRemote Thread****"); MP_Global_connecting[0]=0; }
   else { MP_logl(3,"MP_Init","WifiRemote Thread successfully created"); }
//   Sleep(1000);

   // Now Do the MPExtended thread    
   server[MPEXTENDED]=MPEXTENDED;
   MP_logl(3,"Creating","MPExtended Thread");
   if (CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&Ttcp_client,(LPVOID) &server[MPEXTENDED],0,&dwThreadId[MPEXTENDED]) == NULL)
        { MP_errlog("MP_Init","****Error Creating MPExtended Thread****"); MP_Global_connecting[1]=0; return(0); }
   else { MP_logl(3,"MP_Init","MPExtended Thread successfully created"); }
//   sleep(500); 
   return(1); 
}

//==============================================================================
// routine to start the MP handler
//==============================================================================
extern int __stdcall MP_TCP_Start() 
{
    char status[80];

    MP_logl(3,"MP_TCP_Start: ","Entered");       
    if(MP_Thread_Init()==0) { MP_errlog("MP_TCP_Start","Cannot Connect"); strcpy(status,"Cannot Connect"); }
    else { strcpy(status,"Started"); }
    MP_logl(3,"MP_TCP_Start - Exit status:",status);
}


//==============================================================================
// Send a character string accross the tcp/ip connection
// Note this should really be unicode but hey-ho
//==============================================================================
extern int __stdcall MP_Send(int server,char *msg)
{ int iResult,i,j; char str[MAX_STRING];

  if (MP_Global_connected[server]==0) return 0;            // cant send if not connected
//  MP_log("MP_Send:",msg);
  iResult=send(ConnectSocket[server],msg,strlen(msg),0);     
  if ( iResult == SOCKET_ERROR) 
    {
        sprintf(str,"Unable to send to server: %ld", WSAGetLastError());
        WSACleanup();
        MP_errlog("MP_Send failed:",str);
        return iResult;
    }
  for (i=0;i<strlen(msg);i++) if ( (msg[i]=='\n') ) str[i]=' '; else str[i]=msg[i];
  str[i]=0;
  MP_logl(3,"MP_Send:",str);  
  return iResult;
}

//==============================================================================
// receive data from the tcp/ip connection
// If a single recv fills a buffer then continue to recv until we get a buffer 
// which isn't full - this will be the end of a message
//==============================================================================
extern int __stdcall MP_recv(char *mod, int server, char *recvbuf, int recvbuflen)
{ int i,iResult,iBit; char str[MAX_STRING];

   for (i=0; i<recvbuflen; i++) recvbuf[i]=0;
   iResult = recv(ConnectSocket[server], recvbuf, MAX_BUFBIT, 0); iBit=iResult;
   while ((iBit>0) && (iBit==MAX_BUFBIT))
     { iBit = recv(ConnectSocket[server], &recvbuf[iResult], MAX_BUFBIT, 0);
       if (iBit>0) iResult=iResult+iBit;
     }
   sprintf(str,"MP_Recv:%d bytes recvd",iResult); 
   if (iResult>0) recvbuf[i]=0;
   MP_logl(3,mod,str);
   MP_logl(3,mod,recvbuf);
   return iResult;
}

